home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / Tools / freeWAIS-sf-1.1 / ir / ui.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-05-19  |  16.6 KB  |  673 lines

  1. /* WIDE AREA INFORMATION SERVER SOFTWARE:
  2.    No guarantees or restrictions.  See the readme file for the full standard
  3.    disclaimer.
  4.  
  5.    Brewster@think.com
  6. */
  7.  
  8. /* Copyright (c) CNIDR (see ../COPYRIGHT) */
  9.  
  10.  
  11. #ifndef lint
  12. static char *RCSid = "$Header: /usr/local/ls6/src+data/src/freeWAIS-0.2-sf/ir/RCS/ui.c,v 1.3 1994/05/20 12:57:52 pfeifer Exp $";
  13. #endif
  14.  
  15. /* Change log:
  16.  * $Log: ui.c,v $
  17.  * Revision 1.3  1994/05/20  12:57:52  pfeifer
  18.  * beta
  19.  *
  20.  * Revision 1.2  1994/03/08  21:07:06  pfeifer
  21.  * Patchlevel 04
  22.  *
  23.  * Revision 1.1  1993/02/16  15:05:35  freewais
  24.  * Initial revision
  25.  *
  26.  * Revision 1.16  92/03/18  09:01:09  jonathan
  27.  * don't free DocObjs[0]->Type, it's a copy of the input!
  28.  * 
  29.  * Revision 1.15  92/03/06  12:53:03  jonathan
  30.  * Plug another memory leak.  From ericb@baker.dartmouth.edu (Eric J Bivona).
  31.  * 
  32.  * Revision 1.14  92/02/14  15:26:53  jonathan
  33.  * Conditionalized interpret_message and locally_answer_message so client need
  34.  * not include search engine.
  35.  * 
  36.  * Revision 1.13  92/02/12  13:53:41  jonathan
  37.  * Added "$Log" so RCS will put the log message in the header
  38.  * 
  39.  * 
  40. */
  41.  
  42. /* 
  43.  * this is a simple ui toolkit for building other ui's on top.
  44.  * -brewster
  45.  * 
  46.  * top level functions:
  47.  *   generate_search_apdu
  48.  *   generate_retrieval_apdu
  49.  *   interpret_message
  50.  *
  51.  */
  52.  
  53. /* to do:
  54.  *   generate multiple queries for long documents.
  55.  *     this will crash if the file being retrieved is larger than 100k.
  56.  *   
  57.  */
  58.  
  59. #include "ui.h"
  60. #include "wutil.h"
  61. #include "ustubs.h"
  62. #include "futil.h"
  63.  
  64. #include <ctype.h>
  65. #include <errno.h>
  66. /* #include <string.h> */
  67. #include "cdialect.h"
  68. #include <sys/types.h>
  69.  
  70. /* returns a pointer in the buffer of the first free byte.
  71.    if it overflows, then NULL is returned 
  72.  */
  73. char *
  74. generate_search_apdu(buff,
  75.              buff_len,
  76.              seed_words,
  77.              database_name,
  78.              docobjs,
  79.              maxDocsRetrieved)
  80. char* buff;     /* buffer to hold the apdu */
  81. long *buff_len;    /* length of the buffer changed to reflect new data written */
  82. char *seed_words;    /* string of the seed words */
  83. char *database_name;
  84. DocObj** docobjs;
  85. long maxDocsRetrieved;
  86. {
  87.   /* local variables */
  88.  
  89.   SearchAPDU *search3;
  90.   char  *end_ptr;
  91.   static char *database_names[2] = {"", 0};
  92.   any refID;
  93.   WAISSearch *query;
  94.   refID.size = 1;
  95.   refID.bytes = "3";
  96.  
  97.   database_names[0] = database_name;
  98.   query = makeWAISSearch(seed_words,
  99.                          docobjs, /* DocObjsPtr */
  100.                          0L,
  101.                          1L,     /* DateFactor */
  102.                          0L,     /* BeginDateRange */
  103.                          0L,     /* EndDateRange */
  104.                          maxDocsRetrieved
  105.                          );
  106.  
  107.   search3 = makeSearchAPDU(30L, 
  108.                5000L, /* should be large */
  109.                30L,
  110.                            1L,    /* replace indicator */
  111.                            "",    /* result set name */
  112.                            database_names, /* database name */   
  113.                            QT_RelevanceFeedbackQuery, /* query_type */
  114.                            0L,   /* element name */
  115.                            NULL, /* reference ID */
  116.                            query);
  117.  
  118.   end_ptr = writeSearchAPDU(search3, buff, buff_len);
  119.  
  120.   CSTFreeWAISSearch(query);
  121.   freeSearchAPDU(search3);
  122.   return(end_ptr);
  123. }
  124.  
  125.  
  126. /* returns a pointer into the buffer of the next free byte.
  127.    if it overflowed, then NULL is returned
  128.  */
  129.  
  130. char *
  131.  generate_retrieval_apdu(buff,
  132.             buff_len,
  133.             docID,
  134.             chunk_type,
  135.             start,
  136.             end,
  137.             type,
  138.             database_name)
  139. char *buff;
  140. long *buff_len;    /* length of the buffer changed to reflect new data written */
  141. any *docID;
  142. long chunk_type;
  143. long start;
  144. long end;
  145. char *type;
  146. char *database_name;
  147. {
  148.   SearchAPDU *search;
  149.   char  *end_ptr;
  150.  
  151.   static char *database_names[2];
  152.   static char *element_names[3];
  153.   any refID;
  154.  
  155.   DocObj *DocObjs[2];
  156.   any *query;            /* changed from char* by brewster */
  157.  
  158.   if(NULL == type)
  159.     type = s_strdup("TEXT");
  160.  
  161.   database_names[0] = database_name;
  162.   database_names[1] = NULL;
  163.  
  164.   element_names[0] = " ";
  165.   element_names[1] = ES_DocumentText;
  166.   element_names[2] = NULL;
  167.  
  168.   refID.size = 1;
  169.   refID.bytes = "3";
  170.   
  171.   switch(chunk_type){
  172.   case CT_line: 
  173.     DocObjs[0] = makeDocObjUsingLines(docID, type, start, end);
  174.     break;
  175.   case CT_byte:
  176.     DocObjs[0] = makeDocObjUsingBytes(docID, type, start, end);
  177.     break;
  178.   }
  179.   DocObjs[1] = NULL;
  180.  
  181.   query = makeWAISTextQuery(DocObjs);   
  182.   search = makeSearchAPDU( 10L, 16L, 15L, 
  183.               1L,    /* replace indicator */
  184.               "FOO", /* result set name */
  185.               database_names, /* database name */   
  186.               QT_TextRetrievalQuery, /* query_type */
  187.               element_names, /* element name */
  188.               &refID, /* reference ID */
  189.               query);
  190.   end_ptr = writeSearchAPDU(search, buff, buff_len);
  191.   /* s_free(DocObjs[0]->Type); it's a copy of the input, don't free it! */
  192.   CSTFreeDocObj(DocObjs[0]);
  193.   CSTFreeWAISTextQuery(query);
  194.   freeSearchAPDU(search);
  195.   return(end_ptr);
  196. }
  197.  
  198. /* not currently used 
  199.  
  200. static boolean isnumber _AP((char* string));
  201.  
  202. static boolean isnumber(string)
  203. char *string;
  204. {
  205.   long count;
  206.   for(count = 0; count < strlen(string); count++){
  207.     if(!isdigit(string[count])){
  208.       return(false);
  209.     }
  210.   }
  211.   return(true);
  212. }
  213.  
  214. */
  215.  
  216. /* this will negotiate with server, and returs the maximum buffer size 
  217.    the server can handle.
  218.  
  219.    A connection should be established first using open_socket.
  220.  
  221. */
  222.  
  223. long init_connection(inBuffer, outBuffer, bufferSize, connection, userInfo)
  224. char *inBuffer, *outBuffer;
  225. long bufferSize;
  226. FILE *connection;
  227. char *userInfo;
  228.   InitAPDU* init = NULL;
  229.   InitResponseAPDU* reply = NULL;
  230.   long result;
  231.   /* construct an init */
  232.   init = makeInitAPDU(true,false,false,false,false,bufferSize,bufferSize,
  233.               userInfo,defaultImplementationID(),
  234.               defaultImplementationName(),
  235.               defaultImplementationVersion(),NULL,userInfo);
  236.   /* write it to the buffer */
  237.   result = writeInitAPDU(init,inBuffer+HEADER_LENGTH,&bufferSize) - inBuffer;
  238.  
  239.   if(result < 0){
  240.     freeInitAPDU(init);
  241.     return(-1);
  242.   }
  243.   if(0 ==
  244.      interpret_message(inBuffer,
  245.                result - HEADER_LENGTH,
  246.                outBuffer,
  247.                bufferSize,
  248.                connection,
  249.                false    /* true verbose */    
  250.                )) {
  251.     /* error making a connection */
  252.     return (-1);
  253.   }
  254.   if (readInitResponseAPDU(&reply,outBuffer + HEADER_LENGTH) == NULL){
  255.     freeWAISInitResponse((WAISInitResponse*)reply->UserInformationField);
  256.     freeInitResponseAPDU(reply);
  257.     return(-1);
  258.   }
  259.   if (reply->Result == false)
  260.     {                /* the server declined service */
  261.       freeWAISInitResponse((WAISInitResponse*)reply->UserInformationField);
  262.       freeInitResponseAPDU(reply);
  263.       return(-1);
  264.     }
  265.   else                /* we got a response back */
  266.     { result = reply->MaximumRecordSize;
  267.       freeWAISInitResponse((WAISInitResponse*)reply->UserInformationField);
  268.       freeInitResponseAPDU(reply);
  269.       return(result);
  270.     }
  271. }
  272.  
  273. #ifdef LOCAL_SEARCH
  274. /* returns the length of the response, 0 if an error */
  275. long
  276. locally_answer_message(request_message,
  277.                request_length,
  278.                response_message,
  279.                response_buffer_length)
  280. char *request_message;
  281. long request_length;
  282. char *response_message;
  283. long response_buffer_length;
  284. {
  285.   long request_length_internal = request_length;
  286.   long response_length;
  287.   WAISMessage header;
  288.   long maxBufferSize = response_buffer_length;
  289.  
  290.   readWAISPacketHeader(request_message, &header);
  291.   {
  292.     char length_array[11];
  293.     strncpy(length_array, header.msg_len, 10);
  294.     length_array[10] = '\0';
  295.     request_length_internal = atol(length_array);
  296.   }
  297.   /*
  298.     printf("request length is %ld (%ld from caller)\n", 
  299.     request_length_internal,
  300.     request_length);
  301.     */
  302.   
  303.   response_length =
  304.     interpret_buffer(request_message + HEADER_LENGTH, 
  305.              request_length_internal,
  306.              response_message + HEADER_LENGTH,
  307.              response_buffer_length,
  308.              &maxBufferSize,
  309.              (long)header.hdr_vers,
  310.              NULL);
  311.   if(0 > response_length)
  312.     return(0);
  313.   writeWAISPacketHeader(response_message,
  314.             response_length,
  315.             (long)'z',    /* Z39.50 */
  316.             "DowQuest  ", /* server name */
  317.             (long)NO_COMPRESSION,    /* no compression */
  318.             (long)NO_ENCODING,(long)header.hdr_vers);
  319.   return(response_length);
  320. }
  321. #endif
  322.  
  323. /* this is a safe version of unix 'read' it does all the checking
  324.  * and looping necessary
  325.  * to those trying to modify the transport code to use non-UNIX streams:
  326.  *  This is the function to modify!
  327.  */
  328. long read_from_stream(d,buf,nbytes)
  329. long d;                /* this is the stream */
  330. char *buf;
  331. long nbytes;
  332. {
  333.   long didRead;
  334.   long toRead = nbytes;
  335.   long totalRead = 0;        /* paranoia */
  336.  
  337.   while (toRead > 0){
  338.     didRead = read (d, buf, toRead);
  339.     if(didRead == -1)        /* error*/
  340.       return(-1);
  341.     if(didRead == 0)        /* eof */
  342.       return(-2);        /* maybe this should return 0? */
  343.     toRead -= didRead;
  344.     buf += didRead;
  345.     totalRead += didRead;
  346.   }
  347.   if(totalRead != nbytes)    /* we overread for some reason */
  348.     return(- totalRead);    /* bad news */    
  349.   return(totalRead);
  350. }
  351.  
  352. /* returns the length of the response, 0 if an error */
  353.  
  354. long 
  355. transport_message(connection,
  356.           request_message,
  357.           request_length,
  358.           response_message,
  359.           response_buffer_length)
  360. FILE *connection;
  361. char *request_message;
  362. long request_length;
  363. char *response_message;
  364. long response_buffer_length;
  365. {
  366.   WAISMessage header;
  367.   long response_length;
  368.  
  369.   
  370.   /* Write out message. Read back header. Figure out response length. */
  371.   
  372.   if( request_length + HEADER_LENGTH
  373.      != fwrite (request_message, 1L, request_length + HEADER_LENGTH, connection))
  374.     return 0;
  375.  
  376.   fflush(connection);
  377.  
  378.   /* read for the first '0' */
  379.  
  380.   while(1){
  381.     if(0 > read_from_stream(fileno(connection), response_message, 1))
  382.       return 0;
  383.     if('0' == response_message[0])
  384.       break;
  385.   }
  386.  
  387.   if(0 > read_from_stream(fileno(connection), 
  388.                   response_message + 1, 
  389.                   HEADER_LENGTH - 1))
  390.     return 0;
  391.  
  392.   readWAISPacketHeader(response_message, &header);
  393.   {
  394.     char length_array[11];
  395.     strncpy(length_array, header.msg_len, 10);
  396.     length_array[10] = '\0';
  397.     response_length = atol(length_array);
  398.     /*
  399.       if(verbose){
  400.       printf("WAIS header: '%s' length_array: '%s'\n", 
  401.       response_message, length_array);
  402.       }
  403.       */
  404.     if(response_length > response_buffer_length){
  405.       /* we got a message that is too long, therefore empty the message out,
  406.      and return 0 */
  407.       long i;
  408.       for(i = 0; i < response_length; i++){
  409.     read_from_stream(fileno(connection), 
  410.              response_message + HEADER_LENGTH,
  411.              1);
  412. /*    fread(response_message + HEADER_LENGTH, 1, 1, connection); */
  413.       }
  414.       return(0);
  415.     }
  416.   }
  417.   if(0 > read_from_stream(fileno(connection), 
  418.                   response_message + HEADER_LENGTH,
  419.                   response_length))
  420. /*  if(0 > fread(response_message + HEADER_LENGTH,
  421.            1, response_length, connection)) */
  422.     return 0;
  423.   return(response_length);
  424. }
  425.  
  426.  
  427. /* ------------------------------------------------------------*/
  428.  
  429. /*  Facility to record messages sent and recieved for testing 
  430.     and timing purposes. */
  431.  
  432. /* from c:
  433.  
  434.    putenv(strdup("IR_FILE=/users/menlo-park/brewster/tmp/infile"));
  435.  
  436.    from csh:
  437.  
  438.    setenv IR_FILE /users/menlo-park/brewster/tmp/infile
  439.  
  440.  */
  441.  
  442. boolean environment_variables_read = false; 
  443. char* ir_file_environment_variable = "IR_FILE";
  444. char* ir_file = NULL;
  445.  
  446. void read_environment_variables(host, port)
  447.      char* host;
  448.      char* port;
  449. {
  450.   
  451.   if(!environment_variables_read){
  452.     FILE *stream;
  453.     ir_file = (char*)getenv(ir_file_environment_variable);
  454.     if(ir_file){
  455.       printf("IR_file: %s\n", ir_file);
  456.       stream = fopen(ir_file, "w");
  457.       fprintf(stream, "%s %s\n", host, port);
  458.       fclose(stream);
  459.     }
  460.     environment_variables_read = true;
  461.   }
  462. }
  463.  
  464. /* returns 0 if success */
  465. long write_message_to_file(message, length, filename)
  466.      unsigned char *message;
  467.      long length;
  468.      char*filename;
  469. {
  470.   FILE *stream = fopen(filename, "a");
  471.   if(NULL == stream)
  472.     return(-1);
  473.   
  474.   printf("Writing to file: %s %d characters\n", filename, length);
  475.  
  476.   fprintf(stream, "---------------------------------\n");
  477.   
  478.   if(length != fwrite(message, sizeof(unsigned char), 
  479.               length, stream)){
  480.     perror("fwrite error");
  481.     fclose(stream);
  482.     return(-2);
  483.   }
  484.  
  485.   fprintf(stream, "\n");
  486.  
  487.   if(0 != fclose(stream))
  488.     return(-3);
  489.   return(0);
  490. }  
  491.  
  492. /* ------------------------------------------------------------*/
  493.  
  494. /* returns the number of bytes writeen.  0 if an error */
  495. long
  496. interpret_message(request_message,request_length,
  497.           response_message,
  498.           response_buffer_length,
  499.           connection,
  500.           verbose)
  501. char *request_message;
  502. long request_length; /* length of the buffer */
  503. char *response_message;
  504. long response_buffer_length;
  505. FILE *connection;
  506. boolean verbose;
  507. {
  508.   long response_length;
  509.  
  510.   writeWAISPacketHeader(request_message,
  511.             request_length,
  512.             (long)'z',    /* Z39.50 */
  513.             "wais      ", /* server name */
  514.             (long)NO_COMPRESSION,    /* no compression */
  515.             (long)NO_ENCODING,(long)HEADER_VERSION);
  516.  
  517.   if(ir_file){
  518.     long error_code;
  519.     if(0 != (error_code = 
  520.          write_message_to_file((unsigned char*)request_message, 
  521.                    request_length + HEADER_LENGTH, 
  522.                    ir_file)))
  523.       printf("Error writing log file Code: %d\n", error_code);
  524.   }
  525.     
  526.   if(connection != NULL) {
  527.     if(0 == 
  528.        (response_length =
  529.     transport_message(connection, request_message,
  530.               request_length,
  531.               response_message,
  532.               response_buffer_length)))
  533.       return(0);
  534.   }
  535.   else{
  536. #ifdef LOCAL_SEARCH    
  537.     if(0 == 
  538.        (response_length =
  539.     locally_answer_message(request_message, request_length, 
  540.                    response_message,
  541.                    response_buffer_length)))
  542.       return(0);
  543. #else
  544.     waislog(WLOG_HIGH, WLOG_ERROR, "Local search not supported in this version");
  545.     return(0);
  546. #endif
  547.   }
  548.   if(verbose){
  549.     printf ("decoded %ld bytes: \n", response_length);
  550.     twais_dsply_rsp_apdu(response_message + HEADER_LENGTH, 
  551.              request_length);
  552.   }
  553.   if(ir_file){
  554.     long error_code;
  555.     if(0 != (error_code = 
  556.          write_message_to_file((unsigned char*)response_message, 
  557.                    response_length + HEADER_LENGTH, 
  558.                    ir_file)))
  559.       printf("Error writing log file Code: %d\n", error_code);
  560.   }
  561.   return(response_length);
  562. }
  563.  
  564. /* this closes the connection to the socket.
  565.  * the mythology is that this is cleaner than exiting
  566.  */
  567.  
  568. long close_connection(connection)
  569. FILE *connection;
  570. {
  571.   long result = 0;
  572.   
  573.   if(connection != NULL){
  574.     result = fclose(connection);
  575.   }
  576.   return(result);
  577. }
  578.   
  579. void
  580. display_text_record_completely(record,quote_string_quotes)
  581. WAISDocumentText *record;
  582. boolean quote_string_quotes;
  583. {
  584.   long count;
  585.   /* printf(" Text\n");
  586.      print_any("     DocumentID:  ", record->DocumentID);
  587.      printf("     VersionNumber:  %d\n", record->VersionNumber);
  588.      */
  589.   for(count = 0; count < record->DocumentText->size; count++){
  590.     long ch = (unsigned char)record->DocumentText->bytes[count];
  591.     if(27 == ch){
  592.       /* then we have an escape code */
  593.       /* if the next letter is '(' or ')', then ignore two letters */
  594.       if('(' == record->DocumentText->bytes[count + 1] ||
  595.      ')' == record->DocumentText->bytes[count + 1])
  596.     count += 1;             /* it is a term marker */
  597.       else count += 4;        /* it is a paragraph marker */
  598.     }
  599.     else if (ch == '\t') /* a TAB! */
  600.       putc(ch, stdout);
  601.     else if (isprint(ch)){
  602.       if(quote_string_quotes && ch == '"')
  603.     putc('\\', stdout);
  604.       putc(ch, stdout);
  605.     } 
  606.     else if (ch == '\n' || ch == '\r')
  607.       printf ("\n");
  608.   }
  609. }
  610.  
  611. /* modifies the string to exclude all seeker codes. sets length to
  612.    the new length. */
  613. char *delete_seeker_codes(string,length)
  614. char *string;
  615. long *length;
  616. {
  617.   long original_count; /* index into the original string */
  618.   long new_count = 0; /* index into the collapsed string */
  619.   for(original_count = 0; original_count < *length; original_count++){
  620.     if(27 == string[original_count]){
  621.       /* then we have an escape code */
  622.       /* if the next letter is '(' or ')', then ignore two letters */
  623.       if('(' == string[original_count + 1] ||
  624.     ')' == string[original_count + 1])
  625.      original_count += 1;    /* it is a term marker */
  626.       else original_count += 4; /* it is a paragraph marker */
  627.     }
  628.     else string[new_count++] = string[original_count];
  629.   }
  630.   *length = new_count;
  631.   return(string);
  632. }
  633.  
  634.  
  635.   
  636. /* returns a pointer to a string with good stuff */
  637. char *trim_junk(headline)
  638. char *headline;
  639. {
  640.   long length = strlen(headline) + 1; /* include the trailing null */
  641.   long i,j;
  642.   headline = delete_seeker_codes(headline, &length);
  643.  
  644.  
  645.   /* delete leading spaces */
  646.   for(i=0; i < strlen(headline); i++){
  647.     if(isprint(headline[i])){
  648.       break;
  649.     }
  650.   }
  651.   headline = headline + i;
  652.   /* delete trailing stuff */
  653.   for (i = 0, j = 0; i < strlen(headline)+1; i++) {
  654.     if ((headline[i] != '\r') && (headline[i] != '\n')) {
  655.       headline[j++] = headline[i];
  656.     }
  657.   }
  658.   
  659.  
  660.   for(i=strlen(headline) - 1 ; i > 0; i--){
  661.     if(isprint(headline[i])){
  662.       break;
  663.     }
  664.     headline[i] = '\0';
  665.   }
  666.   
  667.   return(headline);
  668. }
  669.  
  670.  
  671.  
  672.